#include "device_excute.h"
#include "OutputLog.h"
#include "app_timer.h"
#include "bootloader_device_resource.h"
#include "data_store_func.h"
#include "lfs2_port.h"
#include "spi_flash_op.h"
#include "string.h"
#include "system_led.h"

uint8_t device_excute_hard_init(uint8_t led_flash_type)
{
  App_Timer_Init();
  system_led_init(led_flash_type);
  output_log_uart_init(4);
  LOG_D("hard init success and go to next step!");
  return 1;
}
int compare_with_byte(const void *ptr, uint8_t byte, int num)
{
  int i;
  const unsigned char *p = (const unsigned char *)ptr;
  for (i = 0; i < num; ++i)
  {
    if (p[i] != byte)
    {
      return i + 1;
    }
  }
  return 0;
}

uint8_t device_excute_shunt(uint8_t *status)
{
  int ret;
	char no_data[32]={0};
  output_log_uart_init(4);
  ret = data_store_init();
  if (ret < 0)
  {
    device_excute_hard_init(1);
    *status = DEVICE_EXCUTE_ERROR;
    return 1;
  }
//	uint32_t write_d=0X1234;
//	
//	lfs2_parameter_write(32,&write_d,4);	
	
  ret = read_base_paremeter_from_fs(&setting_para);
  if (ret == 0x00) //空文件，直接跳转吧。
  {
    write_base_paremeter_to_fs(&default_parameter);
    *status = DEVICE_EXCUTE_JUMP_APP;
    return 1;
  }
  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], DOWNLOAD_FINISH);
  if (ret == 0)
  {
    device_excute_hard_init(0);
    *status = DEVICE_EXCUTE_MOVE_NEW_APP_TO_LOCAL;
    return 1;
  }
  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], NEW_APP_RUN);
  if (ret == 0)
  {
    *status = DEVICE_EXCUTE_JUMP_APP;
    return 1;
  };
	memset(no_data,0,32);
  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], no_data);
  if (ret == 0)
  {
    *status = DEVICE_EXCUTE_JUMP_APP;
    return 1;
  };

  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], NEW_APP_IS_TOO_BIG);
  if (ret == 0)
  {
    *status = DEVICE_EXCUTE_JUMP_APP;
    return 1;
  };
  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], OLD_APP_CLEAN);
  if (ret == 0)
  {
    device_excute_hard_init(1);
    *status = DEVICE_EXCUTE_ERROR;
    return 1;
  }

  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], FLASH_ERASE_ERROR);
  if (ret == 0)
  {
    device_excute_hard_init(1);
    *status = DEVICE_EXCUTE_ERROR;
    return 1;
  }

  ret = strcmp((const char *)&setting_para.OTA_STATUS[0], NEW_APP_MOVE_FAILD);
  if (ret == 0)
  {
    device_excute_hard_init(1);
    *status = DEVICE_EXCUTE_ERROR;
    return 1;
  }
  device_excute_hard_init(1);
  *status = DEVICE_EXCUTE_ERROR;
  return 1;
}
typedef void (*Function_Pointer)(void);
void app_run(void)
{
  Function_Pointer Jump_To_Application;
  unsigned long JumpAddress;
  if (((*(volatile unsigned long *)RUNNNING_APP_START_ADDRESS) & 0x2FFE0000) == 0x20000000)
  {
    LOG_D("jump to application!");
    JumpAddress = *(volatile unsigned long *)(RUNNNING_APP_START_ADDRESS + 4);
    Jump_To_Application = (Function_Pointer)JumpAddress;
    __set_MSP(*(volatile unsigned long *)RUNNNING_APP_START_ADDRESS);
    Jump_To_Application();
  }
}

uint8_t device_excute_jump_app(uint8_t *status)
{
  app_run();
  return 1;
}
uint8_t read_data[256];
#define SPI_FLASH_ADDR   0x00000000 // SPI-Flash 起始地址
#define STM32_FLASH_ADDR 0x0800C000 // Sector 3 起始地址

/**
 * @brief  把 SPI-Flash 的数据搬到片上 Flash（0x0800C000 起）
 * @param  len  长度（≤16 KB， Sector 3 大小）
 * @retval 0 成功，-1 读失败，-2 写失败
 */
int CopySpiToInternalFlash(uint8_t *buf, uint32_t len)
{
  if (!len || !len)
    return -3;
  uint32_t rd_addr = SPI_FLASH_ADDR;
  uint32_t wr_addr = STM32_FLASH_ADDR;

  FLASH_Unlock();
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

  while (len)
  {
    uint32_t chunk = (len > sizeof(buf)) ? sizeof(buf) : len;
    SoftSPIFlash_Read(rd_addr, buf, chunk);
    for (uint32_t i = 0; i < chunk; i += 4)
    {
      if (FLASH_ProgramWord(wr_addr + i, *(uint32_t *)(buf + i)) != FLASH_COMPLETE)
      {
        FLASH_Lock();
        return -2;
      }
    }

    rd_addr += chunk;
    wr_addr += chunk;
    len -= chunk;
  }

  FLASH_Lock();
  return 0;
}
uint8_t device_excute_move_new_app_to_local(uint8_t *status)
{
  int ret;
  // clean store app
  /**
  * @attention clean running app
  */
  static const uint16_t sec_tab[] = {FLASH_Sector_3, FLASH_Sector_4, FLASH_Sector_5, FLASH_Sector_6, FLASH_Sector_7}; // 连续扇区号
  static const uint16_t sec_KB[] = {16, 80, 208, 336, 464};                                                           // 各扇区累计最大 KB

  uint32_t total = setting_para.OTA_firmware_length;
  uint8_t cnt = 0;

  /* 根据长度算出要擦几个扇区 */
  while (cnt < 5 && total > sec_KB[cnt] * 1024U)
    ++cnt;
  if (cnt == 5)
  { // 太大
    set_ota_status( NEW_APP_IS_TOO_BIG);
    software_reboot();
    return 1;
  }
  /* 擦扇区 */
  set_ota_status(OLD_APP_CLEAN);
  FLASH_Unlock();
  for (uint8_t i = 0; i <= cnt; ++i)
  {
    if (FLASH_EraseSector(sec_tab[i], VoltageRange_3) != FLASH_COMPLETE)
    {
      set_ota_status( FLASH_ERASE_ERROR);
      FLASH_Lock();
      software_reboot();
      return 1;
    }
  }
  FLASH_Lock();
  // return 0;

  /**
     * @attention move new app to local
     */
  ret = CopySpiToInternalFlash(read_data, setting_para.OTA_firmware_length);
  if (ret == 0)
  {
    /* code */
    set_ota_status(NEW_APP_RUN);
    LOG_D("new app move success!");
    software_reboot();
  }
  else
  {
    set_ota_status(NEW_APP_MOVE_FAILD);
    LOG_D("new app move failed!");
    software_reboot();
  }
  return 1;
}

uint8_t device_excute_error(uint8_t *status)
{
  *status = DEVICE_EXCUTE_ERROR;
  return 1;
}

void software_reboot(void)
{
  NVIC_SystemReset();
}
